﻿using System.Collections.Generic;
using System.Linq;
using Castle.Windsor;
using GroceryList.Front.Web.Installers;
using GroceryList.Front.Web.Service;
using GroceryList.Front.Web.ViewModels;
using Xunit;
using System;

namespace GroceryList.Test
{
    public class ListaCompraServiceTest : BaseServiceTest
    {
        private readonly IListaCompraService _listaCompraService;

        public ListaCompraServiceTest()
        {

            var containerWithControllers =
                new WindsorContainer().
                    Install(new PersistenceInstaller()).
                    Install(new RepositoryInstaller()).
                    Install(new AutomapperInstaller()).
                    Install(new ServiceInstaller());
            _listaCompraService = containerWithControllers.Resolve<IListaCompraService>();

        }

        [Fact]
        public void DadoUnNombreUnaFechaYUnaColeccionDeDetallesPuedoCrearUnaListaDeLaCompra()
        {
            const string nombre = "lista";
            var fecha = DateTime.Now;
            var detalles =
                new[]
                {
                    new DetalleDto
                    {
                        Producto = "leche",
                        Cantidad = 1, 
                        Observaciones = "Semidesnatada por favor"
                    }
                };
            var lista =
                new ListaCompraDto
                {
                    Nombre = nombre,
                    Fecha = fecha,
                    DetalleProducto = detalles
                };
            lista = _listaCompraService.GuardarLista(lista);

            Assert.Equal(nombre, lista.Nombre);
            Assert.Equal(fecha, lista.Fecha);
            Assert.NotNull(lista.Codigo);

            Assert.Equal(detalles.Count(), lista.DetalleProducto.Count());
        }

        [Fact]
        public void DadaUnaListaDeLaCompraExistenteSoloAñadoDetallesQueTenganCantidadMayorACero()
        {
            var codigoLista = new Guid("43814d0d-11a8-4b31-a991-f4f83e106406");
            var lista = _listaCompraService.ObtenerLista(codigoLista);

            var detalles = new List<DetalleDto>(lista.DetalleProducto);
            const string productoSinCantidad = "Lechuga";
            const string productoConCantidad = "Galletas";
            detalles.AddRange
                (
                    new[]
                    {
                        new DetalleDto
                        {
                            Producto = productoSinCantidad,
                            Cantidad = 0,
                            Observaciones = ""
                        },
                        new DetalleDto
                        {
                            Producto = productoConCantidad,
                            Cantidad = 10,
                            Observaciones = ""
                        }
                    });

            lista.DetalleProducto = detalles;

            lista = _listaCompraService.GuardarLista(lista);

            Assert.NotNull(lista.DetalleProducto.Where(dp=>dp.Producto==productoConCantidad).FirstOrDefault());
            Assert.Null(lista.DetalleProducto.Where(dp => dp.Producto == productoSinCantidad).FirstOrDefault());
            Assert.Equal(0,lista.DetalleProducto.Where(dp=>dp.Cantidad==0).Count());
        }

        [Fact]
        public void CuandoCreoUnaListaSiDespuesLePasoOtrosDetallesLaListaContendraLosDetallesAntiguosYLosNuevos()
        {
            
            const string nombre = "lista";
            var fecha = DateTime.Now;

            const string leche = "leche";
            var lista =
                new ListaCompraDto
                {
                    Codigo = null,
                    Nombre = nombre,
                    Fecha = fecha,
                    DetalleProducto = new[]
                        {
                            new DetalleDto
                            {
                                Producto = leche,
                                Cantidad = 1, 
                                Observaciones = "Semidesnatada por favor"
                            }
                        }
                };

            lista = _listaCompraService.GuardarLista(lista);

            var codigo = lista.Codigo;

            const string listaModificada = "lista modificada";
            lista.Nombre = listaModificada;
            var dateTime = DateTime.Now.AddDays(1);
            lista.Fecha = dateTime;
            const string lecheCafé = "Leche pack peque";

            lista =
                new ListaCompraDto
                {
                    Codigo = codigo,
                    Nombre = listaModificada,
                    Fecha = dateTime,
                    DetalleProducto = new[]
                                      {
                                          new DetalleDto
                                          {
                                              Producto = lecheCafé,
                                              Cantidad = 2,
                                              Observaciones = "leche 'piqui'"
                                          }
                                      },
                };

            lista = _listaCompraService.GuardarLista(lista);


            Assert.Equal(codigo, lista.Codigo);
            Assert.Equal(listaModificada, lista.Nombre);
            Assert.Equal(dateTime, lista.Fecha);

            Assert.Equal(2,lista.DetalleProducto.Count());
            lista.DetalleProducto.Where(dp => dp.Producto.ToLower() == leche.ToLower()).First();
            lista.DetalleProducto.Where(dp => dp.Producto.ToLower() == lecheCafé.ToLower()).First();
        }

        [Fact]
        public void DadoUnNombreDeProductoPuedoRecuperarSusDatos()
        {
            const string nombre = "leche";
            var producto = _listaCompraService.ObtenerProducto(nombre);

            Assert.NotNull(producto);
            Assert.Equal(nombre.ToLower(), producto.Nombre.ToLower());

        }

        [Fact]
        public void AlCrearUnaListaDeLaCompraQueTieneProductosQueNoExistenElMetodoFalla()
        {
            var lista =
                new ListaCompraDto
                {
                    Nombre = "",
                    Fecha = DateTime.Now,
                    DetalleProducto = new[] {new DetalleDto() {Cantidad = 1, Producto = ""}}
                };
            Assert.Throws(typeof(ArgumentException), ()=>_listaCompraService.GuardarLista(lista));
        }

        [Fact]
        public void DadoUnCodigoDeListaPuedoObtenerLaListaYSusDetalles()
        {
            const string nombre = "lista";
            var fecha = DateTime.Now;
            var detalles =
                new[]
                {
                    new DetalleDto
                    {
                        Producto = "leche",
                        Cantidad = 1, 
                        Observaciones = "Semidesnatada por favor"
                    }
                };
            var listaCompra =
                new ListaCompraDto
                {
                    Nombre = nombre,
                    Fecha = fecha,
                    DetalleProducto = detalles
                };
            listaCompra = _listaCompraService.GuardarLista(listaCompra);

            var codigo = listaCompra.Codigo;

            listaCompra = null;

            listaCompra = _listaCompraService.ObtenerLista((Guid) codigo);


            Assert.Equal(codigo, listaCompra.Codigo);
            Assert.Equal(nombre, listaCompra.Nombre);
            Assert.Equal(fecha, listaCompra.Fecha);

            Assert.True(listaCompra.DetalleProducto.Count() > 0);

        }

        [Fact]
        public void CuandoUnaListadeLaCompraNoEstaCreadaSeMuestranTodosLosProductosComoParteDeLosDetallesPeroSinCantidad()
        {
            var listaCompra = _listaCompraService.ObtenerLista(null);
            var detalles = listaCompra.DetalleProducto;
            Assert.True(listaCompra.DetalleProducto.Count() > 0);
            detalles.Where(pr => pr.Producto == "Leche").First();
            detalles.Where(pr => pr.Producto == "Tomate").First();
            detalles.Where(pr => pr.Producto == "Pavo").First();
        }

        [Fact]
        public void DadaUnaListaPuedoObtenerSoloLosDetallesConAlgunaCantidadParaPodeHacerLaCompraFacilmente()
        {
            var codigoLista = new Guid("43814d0d-11a8-4b31-a991-f4f83e106406");
            var listaCompraDto = _listaCompraService.ObtenerListaModoCompra(codigoLista);
            Assert.Equal(2, listaCompraDto.DetalleProducto.Count());
            listaCompraDto.DetalleProducto.Where(dp => dp.Producto == "Leche").First();
            listaCompraDto.DetalleProducto.Where(dp => dp.Producto == "Pavo").First();
        }

        [Fact]
        public void DadoUnDetalleDeUnaListaPuedoMarcarloComoCompradoYAlObtenerLaListaParaHacerLaCompraElElelementoNoAparecera()
        {
            var codigoLista = new Guid("43814d0d-11a8-4b31-a991-f4f83e106406");
            var listaCompraDto = _listaCompraService.ObtenerListaModoCompra(codigoLista);
            var detalleLeche = listaCompraDto.DetalleProducto.Where(dp => dp.Producto == "Leche").First();

            _listaCompraService.ComprarProductoDeLaLista((Guid)listaCompraDto.Codigo, detalleLeche.Producto);

            listaCompraDto = _listaCompraService.ObtenerListaModoCompra(codigoLista);

            Assert.Equal(1, listaCompraDto.DetalleProducto.Count());
        }

        [Fact]
        public void DadoUnDetalleDeUnaListaPuedoMarcarloComoNoSePuedeComprarYAlObtenerLaListaParaHacerLaCompraElElelementoNoAparecera()
        {
            var codigoLista = new Guid("43814d0d-11a8-4b31-a991-f4f83e106406");
            var listaCompraDto = _listaCompraService.ObtenerListaModoCompra(codigoLista);
            var detalleLeche = listaCompraDto.DetalleProducto.Where(dp => dp.Producto == "Leche").First();

            _listaCompraService.TacharProductoDeLaLista((Guid)listaCompraDto.Codigo, detalleLeche.Producto);

            listaCompraDto = _listaCompraService.ObtenerListaModoCompra(codigoLista);

            Assert.Equal(1, listaCompraDto.DetalleProducto.Count());
        }

        [Fact]
        public void DadaUnaListaYUnTerminoDeBusquedaPuedoObtenerLaListaYLosDetallesQueContenganProductosConDichoTermino()
        {
            var codigoLista = new Guid("43814d0d-11a8-4b31-a991-f4f83e106406");
            const string terminoDeBusqueda = "le";
            var lista = _listaCompraService.ObtenerLista(codigoLista, terminoDeBusqueda);

            Assert.True(lista.DetalleProducto.Count() >= 4);
            lista.DetalleProducto.Where(dp => dp.Producto.ToLower() == "leche").First();
            lista.DetalleProducto.Where(dp => dp.Producto.ToLower() == "galletas").First();
            lista.DetalleProducto.Where(dp => dp.Producto.ToLower() == "lechuga").First();
            lista.DetalleProducto.Where(dp => dp.Producto.ToLower() == "leche pack peque").First();
        }

        [Fact]
        public void PuedoObtenerTodasLasListasDeLaCompraAlmacenadas()
        {
            var lista = _listaCompraService.ObtenerTodas();
            Assert.True(lista.Count()>=1);
            Assert.True(lista.Select(lc => lc.Codigo).Contains(new Guid("43814d0d-11a8-4b31-a991-f4f83e106406")));
        }
    }
}
